package com.jyniubi.core.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyniubi.base.exception.Assert;
import com.jyniubi.base.exception.BussinessException;
import com.jyniubi.base.result.ResponseEnum;
import com.jyniubi.core.listener.DictExcelDataListener;
import com.jyniubi.core.mapper.DictMapper;
import com.jyniubi.core.pojo.dto.ExcelDataDTO;
import com.jyniubi.core.pojo.entity.Dict;
import com.jyniubi.core.service.DictService;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据字典 服务实现类
 * </p>
 *
 * @author jyzhang
 * @since 2024-04-27
 */
@Service
@Slf4j
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {
    @Resource
    private RedisTemplate redisTemplate;
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void importDicts(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream())
                    .excelType(ExcelTypeEnum.XLSX)
                    .sheet(0)
                    .head(ExcelDataDTO.class)
                    .registerReadListener(new DictExcelDataListener(baseMapper))
                    .doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportDicts(HttpServletResponse response){
        try {
            // 这里注意 使用swagger 可能会导致各种问题，请直接用浏览器或者用postman
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("dict_", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("content-disposition",
                    "attachment;filename*=utf-8''" + fileName +
                            new DateTime().toString("yyyy_MM_dd")
                            + ExcelTypeEnum.XLSX.getValue());
            List<Dict> dicts = baseMapper.selectList(null);
            List<ExcelDataDTO> excelDataList = dicts.stream().map(dict -> {
                ExcelDataDTO excelDataDTO = new ExcelDataDTO();
                excelDataDTO.setId(dict.getId());
                excelDataDTO.setDictCode(dict.getDictCode());
                excelDataDTO.setParentId(dict.getParentId());
                excelDataDTO.setName(dict.getName());
                excelDataDTO.setValue(dict.getValue());
                return excelDataDTO;
            }).collect(Collectors.toList());
            EasyExcel.write(response.getOutputStream())
                    .sheet("数据字段")
                    .head(ExcelDataDTO.class)
                    .doWrite(excelDataList);
        } catch (IOException e) {
            throw new BussinessException(ResponseEnum.ERROR.getCode(),"数据字段导出异常");
        }
    }

    @Override
    @Cacheable(value = "dicts:cache",key = "{#parentId}")
    public List<Dict> dictsByParentId(Long parentId) {
//        Object o = redisTemplate.opsForValue().get("dicts:cache" + parentId);
//        if (o != null){
//            log.info("从redis查询数据字典...");
//            return (List<Dict>) o;
//        }
        List<Dict> dictList = this.list(Wrappers.lambdaQuery(Dict.class)
                .eq(Dict::getParentId, parentId));
        dictList.forEach(dict -> {
            int count = this.count(Wrappers.lambdaQuery(Dict.class)
                    .eq(Dict::getParentId, dict.getId()));
            dict.setHasChildren(count>0);
        });
//        log.info("从mysql查询数据字典...");
//        redisTemplate.opsForValue().set("dicts:cache" + parentId,dictList,300, TimeUnit.SECONDS);
        return dictList;
    }

    /**
     * 有个问题，就是删除的时候只能获取数据字段的id，所以加了个pId参数
     * 查询增加缓存前缀的时候是加到pId上的，导致删的时候只能根据pId来找id删除
     * todo：如果有更好的方法可以把pId去掉
     * @param id
     */
    @Override
    @CacheEvict(value = "dicts:cache",key = "#pId")
    public void deleteDictById(String pId,String id) {
        int count = this.count(Wrappers.lambdaQuery(Dict.class)
                .eq(Dict::getParentId, id));
        if (count != 0){
            throw new BussinessException(ResponseEnum.Dict_DEL_ERROR);
        }
        this.removeById(id);
    }

    @Override
    @CacheEvict(value = "dicts:cache",key = "#dict.getParentId()")
    public void saveDict(Dict dict) {
        boolean b = this.save(dict);
        Assert.assertNotTrue(b, ResponseEnum.DICT_INSERT_FALSE);
    }

    @Override
    @CacheEvict(value = "dicts:cache",key = "#dict.getParentId()")
    public void updateByDictId(Dict dict) {
        boolean b = this.updateById(dict);
        Assert.assertNotTrue(b, ResponseEnum.DICT_UPDATE_FALSE);
    }

    @Override
    public Dict getDictByDictCodeAndValue(String dickCode, Integer value) {
        return baseMapper.selectDictByDictCodeAndValue(dickCode,value);
    }
}
